package com.guguskins.back.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.guguskins.back.common.constant.InventoryConstant;
import com.guguskins.back.common.constant.PropConstant;
import com.guguskins.back.common.constant.RecordConstant;
import com.guguskins.back.common.constant.RedisConstant;
import com.guguskins.back.common.enums.ResultStatusEnum;
import com.guguskins.back.common.exception.GlobaStatusException;
import com.guguskins.back.common.exception.GlobalMsgException;
import com.guguskins.back.entity.*;
import com.guguskins.back.entity.bo.*;
import com.guguskins.back.entity.dto.LuckyDrawEggDto;
import com.guguskins.back.entity.vo.BoxPrizeVo;
import com.guguskins.back.entity.vo.LuckDrawVo;
import com.guguskins.back.entity.vo.PageVo;
import com.guguskins.back.entity.vo.PropStandDataDetailVo;
import com.guguskins.back.mapper.GuBoxMapper;
import com.guguskins.back.service.*;
import com.guguskins.back.utils.CommonUtil;
import com.guguskins.back.utils.DateUtil;
import com.guguskins.back.utils.RedisUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cglib.beans.BeanCopier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 盲盒 服务实现类
 * </p>
 *
 * @author mybatis-plus
 * @since 2021-05-14
 */
@Service
public class GuBoxServiceImpl extends ServiceImpl<GuBoxMapper, GuBox> implements GuBoxService {

    @Autowired
    private GuBoxMapper boxMapper;

    @Autowired
    private GuBoxItemService boxItemService;

    @Autowired
    private GuUserService userService;

    @Autowired
    private GuEggLevelService eggLevelService;

    @Autowired
    private GuPropNumService propNumService;

    @Autowired
    private GuPropService propService;

    @Autowired
    private GuInventoryService inventoryService;

    @Autowired
    private GuGoodsService goodsService;

    @Autowired
    private GuRecordService recordService;

    @Autowired
    private GuCurrencyRecordService currencyRecordService;

    @Override
    public PageVo<GuBox> backPage(int p, int size, int category, int state, int type, String searchKey) {
        int index = (p - 1) * size;
        List<GuBox> boxes = boxMapper.getBackPageData(index, size, category, state, type, searchKey);
        boxes.forEach(box -> {
            List<GuGoods> goodsList = goodsService.getGoodsList(box.getBoxId());
            box.setGoodsList(goodsList);
            if (ObjectUtils.isEmpty(box.getCategoryName())) {
                box.setCategoryName("");
            }
//            box.setGoodsListShow(goodsService.calculationRate(goodsList));
        });
        long total = boxMapper.getBackPageTotal(category, state, type, searchKey);
        return new PageVo<>(boxes, total);
    }

    @Override
    public boolean backAdd(SaveBoxBo saveBoxBo) {

        int count = this.count(new LambdaQueryWrapper<GuBox>() {
            {
                eq(GuBox::getBoxName, saveBoxBo.getBoxName());
            }
        });
        if (count > 0) {
            throw new GlobalMsgException("盒子名称已存在");
        }

        GuBox box = new GuBox();
        BeanUtils.copyProperties(saveBoxBo, box);

        return box.insert();
    }

    @Override
    public GuBox backDetail(long boxId) {
        return this.getById(boxId);
    }

    @Override
    public boolean backChangeState(GuBox box) {
        return box.updateById();
    }

    @Override
    public boolean backEdit(EditBoxBo editBoxBo) {

        int count = this.count(new LambdaQueryWrapper<GuBox>() {
            {
                eq(GuBox::getBoxName, editBoxBo.getBoxName());
                ne(GuBox::getBoxId, editBoxBo.getBoxId());
            }
        });
        if (count > 0) {
            throw new GlobalMsgException("盒子名称已存在");
        }

        GuBox box = new GuBox();
        BeanUtils.copyProperties(editBoxBo, box);

        return box.updateById();
    }

    @Override
    public boolean backChangeProbability(GuBoxItem boxItem) {
        return boxItem.updateById();
    }

    @Override
    public List<GuGoods> backGoodsListForIsNo(long boxId, String searchKey) {
        List<Long> itemIds = boxItemService.listObjs(new LambdaQueryWrapper<GuBoxItem>() {
            {
                select(GuBoxItem::getItemId);
                eq(GuBoxItem::getBoxId, boxId);
                eq(GuBoxItem::getState, 1);
            }
        }, o -> Long.parseLong(o.toString()));

        List<GuGoods> goodsList = goodsService.list(new LambdaQueryWrapper<GuGoods>() {
            {
                notIn(!CollectionUtils.isEmpty(itemIds), GuGoods::getGoodsId, itemIds);
                like(!ObjectUtils.isEmpty(searchKey), GuGoods::getGoodsName, searchKey);
            }
        });
        return goodsList;
    }

    @Override
    public boolean backAddGoods(SaveBoxGoodsBo saveBoxGoodsBo) {
        if (CollectionUtils.isEmpty(saveBoxGoodsBo.getBoxItemList())) {
            throw new GlobalMsgException("参数不能为空");
        }
        return boxItemService.saveBatch(saveBoxGoodsBo.getBoxItemList());
    }

    @Override
    public boolean backRemoveGoods(GuBoxItem boxItem) {
//        boxItem.setState(0);
//        return boxItem.updateById();
        return boxItemService.removeById(boxItem.getId());
    }

    /**
     * 查询箱子（使用左外连接，查出goods）
     */
    @Override
    public GuBox getBox(Long boxId) {
        return boxMapper.getBox(boxId);
    }

    /**
     * 盲盒详情页数据
     */
    @Override
    public GuBox getBoxCapacity(Long boxId) {
        GuBox box = this.getBox(boxId);
        List<GuGoods> goodsList = box.getGoodsList();
        goodsList.forEach(goods -> {
            goods.setHighProbability(null);
            goods.setRealProbability(null);
        });
        goodsList.forEach(goods -> {
            if (goods.getGoodsPrice().compareTo(box.getBoxPrice()) >= 0) {
                goods.setGoodsPriceType(1);
            }
        });

        //扩容
        box.setGoodsListCapacity(this.generateGoodsListCapacity(goodsList));
        //分组数据计算概率
        box.setGoodsListShow(goodsService.calculationRate(goodsList));
        box.setGoodsIconUrl(goodsList.stream().max(Comparator.comparing(GuGoods::getGoodsPrice)).orElse(new GuGoods()).getGoodsIconUrl());
        return box;
    }

    /**
     * 扩容
     */
    private List<GuGoods> generateGoodsListCapacity(List<GuGoods> goodsList) {
        List<GuGoods> goodsListCapacity = new ArrayList<>(goodsList);
        if (goodsList.size() < 50) {
            for (int i = goodsList.size(); i < 50; i++) {
                goodsListCapacity.add(goodsList.get((int) (Math.random() * (goodsList.size()))));
            }
        }
        return goodsListCapacity;
    }

    /**
     * 计算爆率
     */
    /*@Override
    public List<GuGoods> calculationRate(List<GuGoods> goodsList) {
        List<GuGoods> result = new ArrayList<>();
        BigDecimal total = goodsList.stream().map(GuGoods::getProbability).reduce(BigDecimal.ZERO, BigDecimal::add);

        goodsList.forEach(goods -> goods.setExplodeRate(goods.getProbability().divide(total, 5, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).stripTrailingZeros().toPlainString() + "%"));

        Map<String, List<GuGoods>> collect = goodsList.stream().collect(Collectors.groupingBy(GuGoods::getGoodsSameId, LinkedHashMap::new, Collectors.toList()));

        Set<String> sameIds = collect.keySet();
        sameIds.forEach(sameId -> {
            GuGoods goods = new GuGoods();
            List<GuGoods> subGoodsList = collect.get(sameId);
            goods.setGoodsSameId(sameId);
            goods.setGoodsShortName(subGoodsList.get(0).getGoodsShortName());
            goods.setGoodsOriginalIconUrl(subGoodsList.get(0).getGoodsOriginalIconUrl());
            goods.setGoodsIconUrl(subGoodsList.get(0).getGoodsIconUrl());
            goods.setGoodsLevel(subGoodsList.get(0).getGoodsLevel());
            *//*BeanCopier copier = BeanCopier.create(GuGoods.class, GuGoods.class, false);
            copier.copy(subGoodsList.get(0), goods, null);*//*
            goods.setSubGoodsList(subGoodsList);
            BigDecimal subTotal = subGoodsList.stream().map(GuGoods::getProbability).reduce(BigDecimal.ZERO, BigDecimal::add);
            goods.setExplodeRate(subTotal.divide(total, 5, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).stripTrailingZeros().toPlainString() + "%");
            result.add(goods);
        });
        return result;
    }
*/

    /**
     * 抽奖
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public LuckDrawVo luckDraw(LuckDrawBo luckDrawBo) {

        List<GuGoods> result = new ArrayList<>();

        //获取箱子信息
        GuBox box = this.getBox(luckDrawBo.getBoxId());
        List<GuGoods> goodsList = box.getGoodsList();

        int userType = 1;

        GuUser user = new GuUser();
        //获取用户信息
        if (luckDrawBo.getType().equals(1)) {
            user = userService.getById(luckDrawBo.getUserId());
            //计算箱子价格
            BigDecimal boxTotalPrice = box.getBoxPrice().multiply(new BigDecimal(luckDrawBo.getTime()));
            if (user.getUserGuCurrency().compareTo(boxTotalPrice) < 0) {
                throw new GlobalMsgException("余额不足");
            }
            user.setUserGuCurrency(user.getUserGuCurrency().subtract(boxTotalPrice));
            user.updateById();
            userType = user.getUserType();
        }
        //抽饰品
        for (int i = 0; i < luckDrawBo.getTime(); i++) {
            GuGoods goods = JSON.parseObject(JSON.toJSONString(this.luckyDrawGoods(userType, goodsList)), GuGoods.class);

            //正式抽奖保存信息
            if (luckDrawBo.getType().equals(1)) {
                GuInventory inventory = inventoryService.addInventory(user.getUserId(), user.getUserSteamId(), InventoryConstant.Type.GOODS, InventoryConstant.Source.BLIND_BOX, box.getBoxId(), goods.getGoodsId(), goods.getGoodsPrice());
                goods.setInventoryId(inventory.getInventoryId());
            }
            result.add(goods);
        }

        //掉落金蛋
        Integer goldenEggNumber = box.getBoxGoldenEgg() > 0 ? this.getEggNumber(box.getBoxGoldenEgg(), luckDrawBo.getTime()) : 0;
        //掉落银弹
        Integer silverEggNumber = box.getBoxSilverEgg() > 0 ? this.getEggNumber(box.getBoxSilverEgg(), luckDrawBo.getTime()) : 0;

        return LuckDrawVo.builder().goodsList(result).goldenEggNumber(goldenEggNumber).silverEggNumber(silverEggNumber).build();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public LuckDrawVo luckDrawInventory(LuckDrawInventoryBo luckDrawInventoryBo) {
        List<GuGoods> result = new ArrayList<>();
        GuUser user = userService.getById(luckDrawInventoryBo.getUserId());

        //获取库存信息
        GuInventory guInventory = inventoryService.getById(luckDrawInventoryBo.getInventoryId());

        if (ObjectUtils.isEmpty(guInventory) || !guInventory.getInventoryType().equals(InventoryConstant.Type.BOX)) {
            throw new GlobalMsgException("参数异常");
        }
        if (!user.getUserSteamId().equals(guInventory.getInventorySteamId())) {
            throw new GlobalMsgException("非法操作");
        }
        if (!guInventory.getInventoryState().equals(InventoryConstant.State.INVENTORY)) {
            throw new GlobalMsgException("箱子状态异常");
        }


        //根据库存获取箱子信息
        GuBox box = this.getBox(guInventory.getInventoryItemId());

        //校验充值金额
        if (box.getBoxType().equals(2)) {
            BigDecimal totalAmount = currencyRecordService.getObj(new QueryWrapper<GuCurrencyRecord>() {
                {
                    select("COALESCE(SUM(cr_amount),0.00) as total");
                    eq("cr_type", 0);
                    eq("cr_source_type", 1);
                    ge("cr_create_time", DateUtil.getTimeAddHours(-24));
                }
            }, o -> new BigDecimal(o.toString()));
            if (totalAmount.compareTo(box.getBoxPrice()) < 0) {
                throw new GlobalMsgException("该箱子有充值限制，充值激活后才可以免费打开");
            }
        }

        List<GuGoods> goodsList = box.getGoodsList();

        //抽饰品
        GuGoods goods = this.luckyDrawGoods(user.getUserType(), goodsList);
        //正式抽奖保存信息
        if (luckDrawInventoryBo.getType().equals(1)) {
            //更改箱子库存状态
            guInventory.setInventoryState(InventoryConstant.State.INVALID);
            if (guInventory.updateById()) {
                //添加库存
                GuInventory inventory = inventoryService.addInventory(user.getUserId(), user.getUserSteamId(), InventoryConstant.Type.GOODS, InventoryConstant.Source.BLIND_BOX, box.getBoxId(), goods.getGoodsId(), goods.getGoodsPrice());
                goods.setInventoryId(inventory.getInventoryId());
            } else {
                throw new GlobalMsgException("开启失败，请重新开启");
            }
        }
        result.add(goods);

        return LuckDrawVo.builder().goodsList(result).build();
    }

    @Override
    public List<GuBox> getBoxes(int boxType) {
        List<GuBox> boxes = boxMapper.getBoxes(boxType);
        boxes.forEach(box -> {
            //分组数据计算概率
            List<GuGoods> goodsList = box.getGoodsList();
            box.setGoodsListShow(goodsService.calculationRate(goodsList).stream().limit(12).collect(Collectors.toList()));
            box.setGoodsIconUrl(goodsList.stream().max(Comparator.comparing(GuGoods::getGoodsPrice)).orElse(new GuGoods()).getGoodsIconUrl());
        });
        return boxes;
    }

    @Override
    public PropStandDataDetailVo propStandDataDetail(int type, Long userId, Long boxId) {
        List<GuBox> boxes;
        List<GuProp> props;

        GuBox box = this.getBox(boxId);

        //0 不刷新箱子 1 刷新箱子 2 第四步刷新箱子
        if (type == 0) {
            RedisUtil.deleteKey(RedisConstant.PROP_STAND_PRIZE_PREFIX + userId + boxId);
            if (RedisUtil.hasKey(RedisConstant.PROP_STAND_PREFIX + userId + boxId)) {
                Map<String, String> map = RedisUtil.getAllHash(RedisConstant.PROP_STAND_PREFIX + userId + boxId);
                boxes = map.keySet().stream().map(key -> JSON.parseObject(map.get(key), GuBox.class)).collect(Collectors.toList());

                boxes.forEach(childBox -> {
                    childBox.setGoodsList(null);
                    childBox.setGoodsListShow(null);
                });
            } else {
                boxes = this.initialDetail(userId, boxId, RedisConstant.PROP_STAND_PREFIX + userId + boxId);
            }
            props = propService.getListByUserId(userId, boxId, null, Collections.singletonList(PropConstant.EXCLUDE_CARD));
        } else if (type == 1) {
            //删除缓存数据，刷新箱子
            RedisUtil.deleteKey(RedisConstant.PROP_STAND_PREFIX + userId + boxId);
            RedisUtil.deleteKey(RedisConstant.PROP_STAND_PRIZE_PREFIX + userId + boxId);
            boxes = this.initialDetail(userId, boxId, RedisConstant.PROP_STAND_PREFIX + userId + boxId);
            props = propService.getListByUserId(userId, boxId, null, Collections.singletonList(PropConstant.EXCLUDE_CARD));
        } else {
            Long hashSize = RedisUtil.getHashSize(RedisConstant.PROP_STAND_PRIZE_PREFIX + userId + boxId);
            if (!ObjectUtils.isEmpty(hashSize) && hashSize == 2) {
                throw new GlobaStatusException(ResultStatusEnum.CASE_IS_OPEN);
            }
            RedisUtil.deleteKey(RedisConstant.PROP_STAND_PREFIX + userId + boxId);
            boxes = this.initialDetail(userId, boxId, RedisConstant.PROP_STAND_PREFIX + userId + boxId + "White");
            props = propService.getListByWhite(userId, Collections.singletonList(PropConstant.EXCLUDE_CARD));
        }
        List<GuProp> eggs = propService.getListByUserId(userId, null, null, Arrays.asList(PropConstant.GOLDEN_EGG, PropConstant.SILVER_EGG));

        return PropStandDataDetailVo.builder().box(box).boxes(boxes).props(props).eggs(eggs).uuid(userId).build();
    }

    /**
     * 初始化道具站9个箱子
     */
    private List<GuBox> initialDetail(Long userId, Long boxId, String redisKey) {
        int userType = 0;
        GuUser user = userService.getById(userId);
        if (!ObjectUtils.isEmpty(user)) {
            userType = user.getUserType();
        }

        GuBox box = this.getBox(boxId);
        //分组数据计算概率
        List<GuGoods> goodsList = box.getGoodsList();
//        List<GuGoods> goodsListShow = this.calculationRate(goodsList);
        BeanCopier copier = BeanCopier.create(GuBox.class, GuBox.class, false);
        //初始化9个小箱子
        for (int i = 0; i < 9; i++) {
            GuGoods goods = this.luckyDrawGoods(userType, goodsList);
            GuBox childBox = new GuBox();
            copier.copy(box, childBox, null);
            childBox.setGoods(goods);
            childBox.setGoodsList(null);
            childBox.setIsDouble(0);
            childBox.setIsWhite(0);
//            childBox.setGoodsListShow(goodsListShow);
            childBox.setId(i);
            RedisUtil.setHashValue(redisKey, String.valueOf(i), JSON.toJSONString(childBox));
        }

        Map<String, String> map = RedisUtil.getAllHash(redisKey);
        return map.keySet().stream().map(key -> JSON.parseObject(map.get(key), GuBox.class)).collect(Collectors.toList());
    }

    /**
     * 使用道具卡
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Object recordCard(Long userId, UseCardBo useCardBo) {

        GuUser user = userService.getById(userId);

        GuPropNum propNum = propNumService.getByUserIdAndPropId(userId, PropConstant.EXCLUDE_CARD);
        if (ObjectUtils.isEmpty(propNum) || propNum.getPropNum() <= 0) {
            throw new GlobalMsgException("道具卡数量为0");
        }
        //判断是不是防白给第二个箱子
        if (RedisUtil.hasKey(RedisConstant.PROP_STAND_PRIZE_PREFIX + userId + useCardBo.getBoxId())) {
            throw new GlobalMsgException("防白给箱子不能使用防白给卡");
        }

        GuBox redisBox;
        switch (useCardBo.getCardType()) {
            case PropConstant.EXCLUDE_CARD:
                List<GuBox> boxes = this.getAllRedisBox(userId, useCardBo.getBoxId());
                if (boxes.stream().anyMatch(guBox -> (!ObjectUtils.isEmpty(guBox.getFlag()) && guBox.getFlag().equals(1)))) {
                    throw new GlobalMsgException("已使用过排除卡");
                }
                List<GuBox> minBoxes = boxes.stream().sorted(Comparator.comparing(guBox -> guBox.getGoods().getGoodsPrice())).limit(3).collect(Collectors.toList());
                minBoxes.forEach(guBox -> {
                    guBox.setFlag(1);
                    RedisUtil.setHashValue(RedisConstant.PROP_STAND_PREFIX + userId + useCardBo.getBoxId(), guBox.getId().toString(), JSON.toJSONString(guBox));
                });
                //扣减卡片
                this.deductAndRecordProp(user, propNum, useCardBo.getBoxId());
                break;
            case PropConstant.CUE_CARD:
                GuBox box = this.getBox(useCardBo.getBoxId());
                List<GuGoods> goodsListShow = goodsService.calculationRate(box.getGoodsList());
                redisBox = JSON.parseObject(RedisUtil.getHashValue(RedisConstant.PROP_STAND_PREFIX + userId + useCardBo.getBoxId(), useCardBo.getId().toString()), GuBox.class);
                if (!ObjectUtils.isEmpty(redisBox.getCueSameId())) {
                    throw new GlobalMsgException("已使用过提示卡");
                }
                //获取提示卡结果
                String cueSameId = this.generateCueGoodsSameId(goodsListShow, redisBox.getGoods());
                if (ObjectUtils.isEmpty(cueSameId)) {
                    throw new GlobalMsgException("暂不能使用提示卡");
                }

                redisBox.setCueSameId(cueSameId);
                redisBox.setExcludeGoods(goodsListShow.stream().filter(goods -> goods.getGoodsSameId().equals(cueSameId)).findFirst().orElse(new GuGoods()));

                //扣减卡片
                this.deductAndRecordProp(user, propNum, useCardBo.getBoxId());

                RedisUtil.setHashValue(RedisConstant.PROP_STAND_PREFIX + userId + useCardBo.getBoxId(), useCardBo.getId().toString(), JSON.toJSONString(redisBox));
                return this.goodsListShow(userId, useCardBo.getBoxId(), useCardBo.getId());
            case PropConstant.DOUBLE_CARD:
                redisBox = JSON.parseObject(RedisUtil.getHashValue(RedisConstant.PROP_STAND_PREFIX + userId + useCardBo.getBoxId(), useCardBo.getId().toString()), GuBox.class);
                if (!ObjectUtils.isEmpty(redisBox.getIsDouble()) && redisBox.getIsDouble().equals(1)) {
                    throw new GlobalMsgException("已使用过翻倍卡");
                }
                redisBox.setIsDouble(1);
                RedisUtil.setHashValue(RedisConstant.PROP_STAND_PREFIX + userId + useCardBo.getBoxId(), useCardBo.getId().toString(), JSON.toJSONString(redisBox));
                break;
            case PropConstant.WHITE_CARD:
                redisBox = JSON.parseObject(RedisUtil.getHashValue(RedisConstant.PROP_STAND_PREFIX + userId + useCardBo.getBoxId(), useCardBo.getId().toString()), GuBox.class);
                if (!ObjectUtils.isEmpty(redisBox.getIsWhite()) && redisBox.getIsWhite().equals(1)) {
                    throw new GlobalMsgException("已使用过防白给卡");
                }
                redisBox.setIsWhite(1);
                RedisUtil.setHashValue(RedisConstant.PROP_STAND_PREFIX + userId + useCardBo.getBoxId(), useCardBo.getId().toString(), JSON.toJSONString(redisBox));
                break;
            default:
                throw new GlobalMsgException("未知道具卡类型");
        }
        return null;
    }

    @Override
    public Object cancelCard(Long userId, UseCardBo useCardBo) {
        GuUser user = userService.getById(userId);

        GuPropNum propNum = propNumService.getByUserIdAndPropId(userId, PropConstant.EXCLUDE_CARD);
        if (ObjectUtils.isEmpty(propNum) || propNum.getPropNum() <= 0) {
            throw new GlobalMsgException("道具卡数量为0");
        }
        //判断是不是防白给第二个箱子
        if (RedisUtil.hasKey(RedisConstant.PROP_STAND_PRIZE_PREFIX + userId + useCardBo.getBoxId())) {
            throw new GlobalMsgException("防白给箱子不能使用防白给卡");
        }

        GuBox redisBox;
        switch (useCardBo.getCardType()) {
            case PropConstant.DOUBLE_CARD:
                redisBox = JSON.parseObject(RedisUtil.getHashValue(RedisConstant.PROP_STAND_PREFIX + userId + useCardBo.getBoxId(), useCardBo.getId().toString()), GuBox.class);
                if (!ObjectUtils.isEmpty(redisBox.getIsDouble()) && redisBox.getIsDouble().equals(0)) {
                    throw new GlobalMsgException("未使用过翻倍卡");
                }
                redisBox.setIsDouble(0);
                RedisUtil.setHashValue(RedisConstant.PROP_STAND_PREFIX + userId + useCardBo.getBoxId(), useCardBo.getId().toString(), JSON.toJSONString(redisBox));
                break;
            case PropConstant.WHITE_CARD:
                redisBox = JSON.parseObject(RedisUtil.getHashValue(RedisConstant.PROP_STAND_PREFIX + userId + useCardBo.getBoxId(), useCardBo.getId().toString()), GuBox.class);
                if (!ObjectUtils.isEmpty(redisBox.getIsWhite()) && redisBox.getIsWhite().equals(0)) {
                    throw new GlobalMsgException("未使用过防白给卡");
                }
                redisBox.setIsWhite(0);
                RedisUtil.setHashValue(RedisConstant.PROP_STAND_PREFIX + userId + useCardBo.getBoxId(), useCardBo.getId().toString(), JSON.toJSONString(redisBox));
                break;
            default:
                throw new GlobalMsgException("未知道具卡类型");
        }
        return null;
    }

    private List<GuBox> getAllRedisBox(Long userId, Long boxId) {
        Map<String, String> map = RedisUtil.getAllHash(RedisConstant.PROP_STAND_PREFIX + userId + boxId);
        return map.keySet().stream().map(key -> JSON.parseObject(map.get(key), GuBox.class)).collect(Collectors.toList());
    }

    /**
     * 扣减并记录道具使用
     */
    private void deductAndRecordProp(GuUser user, GuPropNum propNum, Long boxId) {
        //道具卡库存-1
        propNum.setPropNum(propNum.getPropNum() - 1);
        propNum.updateById();
        // 记录
        recordService.addRecord(user.getUserId(), RecordConstant.TYPE.USE, InventoryConstant.Source.PROP_STAND, boxId, InventoryConstant.Type.PROP, propNum.getPropId(), "道具站使用道具卡", "");
    }

    private String generateCueGoodsSameId(List<GuGoods> goodsListShow, GuGoods goods) {
        List<String> sameIds = goodsListShow.stream().map(GuGoods::getGoodsSameId).filter(goodsSameId -> !goodsSameId.equals(goods.getGoodsSameId())).collect(Collectors.toList());
        int i = (int) (Math.random() * sameIds.size());
        return sameIds.size() > 0 ? sameIds.get(i) : null;
    }

    @Override
    public List<GuGoods> goodsListShow(Long userId, Long boxId, Integer id) {

        GuBox box = this.getBox(boxId);
        List<GuGoods> goodsList = box.getGoodsList();
        goodsList.forEach(goods -> {
            if (goods.getGoodsPrice().compareTo(box.getBoxPrice()) >= 0) {
                goods.setGoodsPriceType(1);
            }
        });
        List<GuGoods> goodsListShow = goodsService.calculationRate(goodsList);
        if (!ObjectUtils.isEmpty(id)) {
            String hashValue = RedisUtil.getHashValue(RedisConstant.PROP_STAND_PREFIX + userId + boxId, id.toString());
            if (!ObjectUtils.isEmpty(hashValue)) {
                GuBox redisBox = JSON.parseObject(hashValue, GuBox.class);
                if (!ObjectUtils.isEmpty(redisBox.getCueSameId())) {
                    goodsListShow.forEach(goods -> {
                        if (goods.getGoodsSameId().equals(redisBox.getCueSameId())) {
                            goods.setFlag(1);
                        }
                    });
                }
            }
        }
        return goodsListShow;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BoxPrizeVo getPrize(Long userId, UseCardBo useCardBo) {
//        List<BoxPrizeVo> boxPrizeVos = new ArrayList<>();
        GuUser user = userService.getById(userId);
        if (ObjectUtils.isEmpty(user)) {
            throw new GlobalMsgException("未知用户");
        }

        GuBox box = this.getBox(useCardBo.getBoxId());

        //扣除余额
        //计算箱子价格
        if (user.getUserGuCurrency().compareTo(box.getBoxPrice()) < 0) {
            throw new GlobalMsgException("余额不足");
        }
        user.setUserGuCurrency(user.getUserGuCurrency().subtract(box.getBoxPrice()));
        boolean result = user.updateById();
        if (!result) {
            throw new GlobalMsgException("扣除余额失败");
        }

        String hashValue = RedisUtil.getHashValue(RedisConstant.PROP_STAND_PREFIX + userId + useCardBo.getBoxId(), useCardBo.getId().toString());
        GuBox redisBox = JSON.parseObject(hashValue, GuBox.class);

        //直接存入仓库
        int num = 1;
        if (!ObjectUtils.isEmpty(redisBox.getIsDouble()) && redisBox.getIsDouble().equals(1)) {
            num = 2;
            //扣除卡片
            this.deductAndRecordProp(user, propNumService.getByUserIdAndPropId(userId, PropConstant.DOUBLE_CARD), box.getBoxId());
        }
        List<GuGoods> goodsList = new ArrayList<>();
        for (int i = 0; i < num; i++) {
            GuGoods goods = JSON.parseObject(JSON.toJSONString(redisBox.getGoods()), GuGoods.class);
            GuInventory inventory = inventoryService.addInventory(user.getUserId(), user.getUserSteamId(), InventoryConstant.Type.GOODS, InventoryConstant.Source.PROP_STAND, box.getBoxId(), goods.getGoodsId(), goods.getGoodsPrice());
            goods.setInventoryId(inventory.getInventoryId());
            goodsList.add(goods);
        }
        BoxPrizeVo boxPrizeVo = BoxPrizeVo.builder().goodsList(goodsList).goods(goodsList.get(0)).isWhite(redisBox.getIsWhite()).isDouble(redisBox.getIsDouble()).id(0).build();
        RedisUtil.deleteKey(RedisConstant.PROP_STAND_PREFIX + userId + useCardBo.getBoxId());

        //走防白给步骤
        if (!ObjectUtils.isEmpty(redisBox.getIsWhite()) && redisBox.getIsWhite().equals(1)) {
            //redis存放奖品，走刷新步骤2流程
            RedisUtil.setHashValue(RedisConstant.PROP_STAND_PRIZE_PREFIX + userId + redisBox.getBoxId(), "0", JSON.toJSONString(boxPrizeVo));
            //删除上一批奖品
            RedisUtil.deleteKey(RedisConstant.PROP_STAND_PREFIX + userId + useCardBo.getBoxId());
        }
        return boxPrizeVo;
    }

    @Override
    public PropStandDataDetailVo propStandDataDetailById(Long userId, Long boxId, int id) {

        String hashValue = RedisUtil.getHashValue(RedisConstant.PROP_STAND_PREFIX + userId + boxId, String.valueOf(id));
        if (ObjectUtils.isEmpty(hashValue)) {
            throw new GlobaStatusException(ResultStatusEnum.CASE_IS_OPEN);
        }
        hashValue = RedisUtil.getHashValue(RedisConstant.PROP_STAND_PREFIX + userId + boxId, String.valueOf(id));
        GuBox box = JSON.parseObject(hashValue, GuBox.class);
        List<GuProp> props = propService.getListByUserId(userId, boxId, id, Arrays.asList(PropConstant.CUE_CARD, PropConstant.DOUBLE_CARD, PropConstant.WHITE_CARD));
        List<GuProp> eggs = propService.getListByUserId(userId, null, null, Arrays.asList(PropConstant.GOLDEN_EGG, PropConstant.SILVER_EGG));
        return PropStandDataDetailVo.builder().box(box).props(props).eggs(eggs).build();
    }

    @Override
    public List<BoxPrizeVo> getWhitePrize(Long userId, UseCardBo useCardBo) {

        GuUser user = userService.getById(userId);
        GuBox box = this.getBox(useCardBo.getBoxId());

        List<BoxPrizeVo> boxPrizeVos = new ArrayList<>(2);
        String value = RedisUtil.getHashValue(RedisConstant.PROP_STAND_PRIZE_PREFIX + userId + useCardBo.getBoxId(), "0");
        if (ObjectUtils.isEmpty(value)) {
            //如果防白给缓存数据为空，直接返回第一步
            throw new GlobaStatusException(ResultStatusEnum.CASE_IS_OPEN);
        }
        BoxPrizeVo boxPrizeVoOld = JSON.parseObject(value, BoxPrizeVo.class);
        boxPrizeVos.add(boxPrizeVoOld);
        int num = 1;
        if (!ObjectUtils.isEmpty(boxPrizeVoOld.getIsDouble()) && boxPrizeVoOld.getIsDouble().equals(1)) {
            num = 2;
        }
        //获取防白给箱子
        String hashValue = RedisUtil.getHashValue(RedisConstant.PROP_STAND_PREFIX + userId + useCardBo.getBoxId() + "White", useCardBo.getId().toString());
        GuBox redisBox = JSON.parseObject(hashValue, GuBox.class);

        List<GuGoods> goodsList = new ArrayList<>();
        for (int i = 0; i < num; i++) {
            GuGoods goods = JSON.parseObject(JSON.toJSONString(redisBox.getGoods()), GuGoods.class);
            GuInventory inventory = inventoryService.addInventory(user.getUserId(), user.getUserSteamId(), InventoryConstant.Type.GOODS, InventoryConstant.Source.PROP_STAND, box.getBoxId(), goods.getGoodsId(), goods.getGoodsPrice());
            goods.setInventoryId(inventory.getInventoryId());
            goodsList.add(goods);
        }
        BoxPrizeVo boxPrizeVo = BoxPrizeVo.builder().goodsList(goodsList).goods(goodsList.get(0)).isWhite(redisBox.getIsWhite()).id(1).isDouble(boxPrizeVoOld.getIsDouble()).build();
        boxPrizeVos.add(boxPrizeVo);
        RedisUtil.setHashValue(RedisConstant.PROP_STAND_PRIZE_PREFIX + userId + redisBox.getBoxId(), "1", JSON.toJSONString(boxPrizeVo));
        RedisUtil.deleteKey(RedisConstant.PROP_STAND_PREFIX + userId + useCardBo.getBoxId() + "White");
//        RedisUtil.setKey()
        return boxPrizeVos;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BoxPrizeVo putInventory(Long userId, UseCardBo useCardBo) {
        //没有数据直接返回第一步
        if (!RedisUtil.hasKey(RedisConstant.PROP_STAND_PRIZE_PREFIX + userId + useCardBo.getBoxId())) {
            throw new GlobaStatusException(ResultStatusEnum.CASE_IS_OPEN);
        }
        Map<String, String> allHash = RedisUtil.getAllHash(RedisConstant.PROP_STAND_PRIZE_PREFIX + userId + useCardBo.getBoxId());
        //已经放入库存，如果选择1那就修改0为失效1为有效
        if (useCardBo.getId().equals(1)) {
            //修改失效
            BoxPrizeVo boxPrizeVoFailure = JSON.parseObject(allHash.get("0"), BoxPrizeVo.class);
            inventoryService.updateRecordStateByIds(boxPrizeVoFailure.getGoodsList().stream().map(GuGoods::getInventoryId).collect(Collectors.toList()), InventoryConstant.State.INVALID);
            //修改生效
            BoxPrizeVo boxPrizeVoTakeEffect = JSON.parseObject(allHash.get("1"), BoxPrizeVo.class);
            inventoryService.updateRecordStateByIds(boxPrizeVoTakeEffect.getGoodsList().stream().map(GuGoods::getInventoryId).collect(Collectors.toList()), InventoryConstant.State.INVENTORY);
        }
        return JSON.parseObject(allHash.get(useCardBo.getId().toString()), BoxPrizeVo.class);
    }

//    @Override
//    @Transactional(rollbackFor = Exception.class)
//    public void exchangeGuCurrency(Long userId, UseCardBo useCardBo) {
//        //没有数据直接返回第一步
//        if (!RedisUtil.hasKey(RedisConstant.PROP_STAND_PRIZE_PREFIX + userId + useCardBo.getBoxId())) {
//            throw new GlobaStatusException(ResultStatusEnum.CASE_IS_OPEN);
//        }
//        GuUser user = userService.getById(userId);
//        Map<String, String> allHash = RedisUtil.getAllHash(RedisConstant.PROP_STAND_PRIZE_PREFIX + userId + useCardBo.getBoxId());
//        //如果选择1那就修改0为失效1为有效
//        if (useCardBo.getId().equals(1)) {
//            //修改失效
//            BoxPrizeVo boxPrizeVoFailure = JSON.parseObject(allHash.get("0"), BoxPrizeVo.class);
//            inventoryService.updateRecordStateByIds(boxPrizeVoFailure.getInventoryIds(), InventoryConstant.State.INVALID);
//        }
//        //兑换咕币
//        BigDecimal totalPrice = BigDecimal.ZERO;
//        //获取兑换咕币的数量
//        String s = allHash.get(useCardBo.getId().toString());
//        BoxPrizeVo boxPrizeVo = JSON.parseObject(s, BoxPrizeVo.class);
//        List<GuInventory> inventories = inventoryService.listByIds(boxPrizeVo.getInventoryIds());
//        for (GuInventory inventory : inventories) {
//            GuGoods goods = goodsService.getById(inventory.getInventoryItemId());
//            totalPrice = totalPrice.add(goods.getGoodsPrice());
//            inventory.setInventoryState(InventoryConstant.State.EXCHANGE_GOO_CURRENCY);
//        }
//        if (inventoryService.updateBatchById(inventories)) {
//            //增加咕币
//            user.setUserGuCurrency(user.getUserGuCurrency().add(totalPrice));
//            user.updateById();
//            //记录日志
//        }
//    }

    /**
     * 获取鸡蛋数量
     */
    private Integer getEggNumber(Integer eggLevelId, Integer time) {
        GuEggLevel eggLevel = eggLevelService.getById(eggLevelId);
        LuckyDrawEggDto luckyDrawEggDTO;
        if (time >= 5) {
            luckyDrawEggDTO = LuckyDrawEggDto.builder().probability(eggLevel.getHighProbability()).max(eggLevel.getMax()).min(eggLevel.getMin()).build();
        } else {
            luckyDrawEggDTO = LuckyDrawEggDto.builder().probability(eggLevel.getProbability()).max(eggLevel.getMax()).min(eggLevel.getMin()).build();
        }
        //掉落鸡蛋
        return CommonUtil.luckyDrawEgg(luckyDrawEggDTO);
    }

    /**
     * 抽奖
     */
    private GuGoods luckyDrawGoods(Integer userType, List<GuGoods> goodsList) {
        //创建区间数组
        /*List<BigDecimal> interval = new ArrayList<>();
        BigDecimal start = new BigDecimal(BigInteger.ZERO);
        interval.add(start);
        for (LuckyDrawDto luckyDrawDTO : luckyDrawDTOS) {
            start = start.add(luckyDrawDTO.getProbability());
            interval.add(start);
        }*/
        //生成随机数
        BigDecimal random;
        if (userType.equals(1)) {
            random = BigDecimal.valueOf(Math.random() * (goodsList.stream().map(GuGoods::getProbability).reduce(BigDecimal.ZERO, BigDecimal::add)).doubleValue());
        } else {
            random = BigDecimal.valueOf(Math.random() * (goodsList.stream().map(GuGoods::getHighProbability).reduce(BigDecimal.ZERO, BigDecimal::add)).doubleValue());
        }
        //比对区间
        BigDecimal start = new BigDecimal(BigInteger.ZERO);
        for (GuGoods goods : goodsList) {
            start = start.add(userType.equals(1) ? goods.getHighProbability() : goods.getProbability());
            if (random.compareTo(start) < 0) {
                return goods;
            }
        }
        return this.luckyDrawGoods(userType, goodsList);
    }
}
